﻿using iTool.Cloud.Center;
using iTool.Cloud.Center.Model;
using iTool.Clustering.Center.ServiceProvider;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Orleans;
using Orleans.Configuration;
using Orleans.Runtime;
using Orleans.Serialization;
using Orleans.Storage;
using System;
using System.Threading;
using System.Threading.Tasks;

namespace iTool.Clustering.Center.Membership
{
    public class iCenterStorageProvider : IGrainStorage, ILifecycleParticipant<ISiloLifecycle>
    {
        private readonly JsonSerializerSettings jsonSettings;



        private IClusterStorageService grain;
        private ClusterOptions clusterOptions;
        private readonly string providerName;

        public iCenterStorageProvider(iCenterClusterClient client, ITypeResolver typeResolver, IGrainFactory grainFactory, IOptions<ClusteringStaticOptions> options, IOptions<ClusterOptions> clusterOptions, string providerName)
        {
            jsonSettings = OrleansJsonSerializer.GetDefaultSerializerSettings(typeResolver, grainFactory);

            this.providerName = providerName;
            this.clusterOptions = clusterOptions.Value;
            //var builder = new iToolClientBuilder();
            //builder.UseiCenterClustering(options.Value);
            //var client = builder.BuildAndConnectAsync().Result;
            this.grain = client.GetGrain<IClusterStorageService>(new Random().Next(111_111_111, 999_999_999), string.Format("{0},p:{1}",this.clusterOptions.ToKeyString(),this.providerName));
        }

        public async Task ClearStateAsync(string grainType, GrainReference grainReference, IGrainState grainState)
        {
            System.IO.File.AppendAllText(String.Format("{0}_ClearStateAsync_log.txt", this.providerName), JsonConvert.SerializeObject(grainState.State));
            await this.grain.ClearStateAsync(grainType, grainReference.PrimaryKeyAsString(clusterOptions));
        }

        public async Task ReadStateAsync(string grainType, GrainReference grainReference, IGrainState grainState)
        {

            var value = await this.grain.ReadStateAsync(grainType, grainReference.PrimaryKeyAsString(clusterOptions));

            //if ("PubSubStore" == this.providerName)
            //{
            //    System.IO.File.AppendAllText(String.Format("{0}_ReadStateAsync_log.txt", this.providerName), value);
            //}

            //var result = string.IsNullOrWhiteSpace(value) ? null : JsonConvert.DeserializeObject<IState>(value);
            var type = grainState.State.GetType();
            grainState.State =
                string.IsNullOrWhiteSpace(value) ?
                Activator.CreateInstance(type) :
                JsonConvert.DeserializeObject(value, type, jsonSettings);
            grainState.ETag = String.Empty;
        }

        public async Task WriteStateAsync(string grainType, GrainReference grainReference, IGrainState grainState)
        {
            //if ("PubSubStore" == this.providerName)
            //{
            //    System.IO.File.AppendAllText(String.Format("{0}_WriteStateAsync1_log.txt", this.providerName), JsonConvert.SerializeObject(grainState.State));
            //    System.IO.File.AppendAllText(String.Format("{0}_WriteStateAsync2_log.txt", this.providerName), JsonConvert.SerializeObject(grainState.State, jsonSettings));
            //}

            await System.IO.File.AppendAllTextAsync($"./WriteStateAsync.txt", JsonConvert.SerializeObject(new {
                key = grainReference.PrimaryKeyAsString(clusterOptions),
                grainState.State
            })+"\n\n");


            await this.grain.WriteStateAsync(grainType, grainReference.PrimaryKeyAsString(clusterOptions), grainState.State == null ? string.Empty : JsonConvert.SerializeObject(grainState.State, jsonSettings), grainState.ETag);
        }

        #region ILifecycleParticipant<ISiloLifecycle> (执行优先级 1)
        public void Participate(ISiloLifecycle lifecycle)
        {
            lifecycle.Subscribe<iCenterStorageProvider>(ServiceLifecycleStage.ApplicationServices, Init, Close);
        }


        public Task Init(CancellationToken ct)
        {
            return Task.CompletedTask;
        }

        public Task Close(CancellationToken ct)
        {
            return Task.CompletedTask;
        }

        #endregion
    }

    class IState
    {
        public string? State { get; set; }
        public string? ETag { get; set; }
    }
}
